<!--
 * @Description: 
 * @Version: V1.0.0
 * @Author: 周艳凯 484894717@qq.com
 * @Date: 2024-10-21 15:32:48
 * @LastEditors: 周艳凯 484894717@qq.com
 * @LastEditTime: 2024-10-29 17:53:26
 * @FilePath: index.vue
 * Copyright 2024 Marvin, All Rights Reserved. 
 * 2024-10-21 15:32:48
-->
<template>
  <slot />
  <ImagePreview
    v-bind="{ ...$attrs, groupArrowProps }"
    in-group
    :src="currentUrl"
    :visible="mergedVisible"
    @close="onClose"
  >
    <template #actions>
      <slot name="preview-actions" />
    </template>
  </ImagePreview>
</template>

<script lang="ts">
import { computed, defineComponent, provide, reactive, ref, toRefs } from "vue";
import ImagePreview from "./image-preview.vue";
import { props } from "./props";
import useMergeState from "@/ArcoUni/hook/use-merge-state";
import { PreviewGroupInjectionKey } from "./context";
import { isArray, isUndefined } from "@/utils/is";
const Switch = defineComponent({
  name: "SwitcH",
  options: {
    // 虚拟化节点
    virtualHost: true,
  },
  components: {
    ImagePreview,
  },
  props,
  emits: [
    /**
     * @zh 切换图片
     * @en Image switch
     * @param {number} index
     */
    "change",
    "update:current",
    /**
     * @zh 预览的打开和关闭
     * @en Preview visibility change
     * @param {boolean} visible
     */
    "visible-change",
    "update:visible",
  ],
  setup(props, { emit }) {
    const {
      srcList,
      visible,
      defaultVisible,
      current,
      defaultCurrent,
      infinite,
    } = toRefs(props);
    const prefixCls = "arco-image";

    const [mergedVisible, setLocalVisible] = useMergeState(
      defaultVisible.value,
      reactive({
        value: visible,
      }),
    );

    const setVisible = (newVisible: boolean) => {
      if (newVisible !== mergedVisible.value) {
        emit("visible-change", newVisible);
        emit("update:visible", newVisible);
        setLocalVisible(newVisible);
      }
    };

    const propImageUrlMap = computed(
      () =>
        new Map(
          isArray(srcList?.value)
            ? srcList?.value.map((url, index) => [
                index,
                { url, canPreview: true },
              ])
            : [],
        ),
    );

    const imageUrlMap = ref(new Map(propImageUrlMap.value || []));

    const imageIdList = computed(() => Array.from(imageUrlMap.value.keys()));

    const imageCount = computed(() => imageIdList.value.length);

    const [currentIndex, setLocalCurrentIndex] = useMergeState(
      defaultCurrent.value,
      reactive({
        value: current,
      }),
    );
    const setCurrentIndex = (index: number) => {
      if (index !== currentIndex.value) {
        emit("change", index);
        emit("update:current", index);
        setLocalCurrentIndex(index);
      }
    };

    const setCurrentId = (nextId: number) => {
      const nextIndex = imageIdList.value.indexOf(nextId);
      if (nextIndex !== currentIndex.value) {
        setCurrentIndex(nextIndex);
      }
    };

    function registerImageUrl(id: number, url: string, canPreview: boolean) {
      if (!propImageUrlMap.value.has(id))
        imageUrlMap.value.set(id, {
          url,
          canPreview,
        });

      return function unRegisterPreviewUrl() {
        if (!propImageUrlMap.value.has(id)) {
          imageUrlMap.value.delete(id);
        }
      };
    }

    const nextIndex = computed(() => {
      const findNext = (start: number, end: number) => {
        for (let i = start; i <= end; i++) {
          const id = imageIdList.value[i];
          if (imageUrlMap.value.get(id)?.canPreview) {
            return i;
          }
        }
        return undefined;
      };

      const next = findNext(currentIndex.value + 1, imageCount.value - 1);
      return isUndefined(next) && infinite.value
        ? findNext(0, currentIndex.value - 1)
        : next;
    });

    const prevIndex = computed(() => {
      const findPrev = (start: number, end: number) => {
        for (let i = start; i >= end; i--) {
          const id = imageIdList.value[i];
          if (imageUrlMap.value.get(id)?.canPreview) {
            return i;
          }
        }
        return undefined;
      };

      const prev = findPrev(currentIndex.value - 1, 0);
      return isUndefined(prev) && infinite.value
        ? findPrev(imageCount.value - 1, currentIndex.value + 1)
        : prev;
    });

    const currentId = computed(() => imageIdList.value[currentIndex.value]);

    const currentUrl = computed(
      () => imageUrlMap.value.get(currentId.value)?.url,
    );

    provide(
      PreviewGroupInjectionKey,
      reactive({
        registerImageUrl,
        preview: (imageId: number) => {
          setVisible(true);
          setCurrentId(imageId);
          console.log(imageUrlMap.value, "我夏素可");
        },
      }),
    );

    const onPrev = computed(() =>
      !isUndefined(prevIndex.value)
        ? () => {
            // eslint-disable-next-line @typescript-eslint/no-unused-expressions
            !isUndefined(prevIndex.value) && setCurrentIndex(prevIndex.value);
          }
        : undefined,
    );

    const onNext = computed(() =>
      !isUndefined(nextIndex.value)
        ? () => {
            // eslint-disable-next-line @typescript-eslint/no-unused-expressions
            !isUndefined(nextIndex.value) && setCurrentIndex(nextIndex.value);
          }
        : undefined,
    );

    return {
      prefixCls,
      visible,
      prevIndex,
      nextIndex,
      currentUrl,
      mergedVisible,
      onClose() {
        setVisible(false);
      },
      groupArrowProps: reactive({
        onPrev,
        onNext,
      }),
    };
  },
});
export default Switch;
</script>
